Fix phpstan/phpstan#2572: Optional templated args not provided cause unbound template errors#5175
Conversation
2f136f2 to
48fb718
Compare
|
The fix seems interesting but I cannot reproduce the error from https://github.com/phpstan/phpstan-src/actions/runs/23582513270/job/68668407276?pr=5175 Can you @staabm ? |
…rams - When a template type is only used on a variadic parameter and no arguments are passed, it was incorrectly reported as unresolvable - Fixed by inferring NeverType for variadic parameters with no arguments in GenericParametersAcceptorResolver, since an empty variadic means the element type is never - Added regression tests in both rule test and NSRT format Closes phpstan/phpstan#2572
48fb718 to
ae5b8bf
Compare
|
I can reproduce it when using the phpstan.phar from this PRs artifacts and put it into vendor/phpstan/phpstan/phpstan.phar and run will try to create a reproducer now |
|
can reproduce within phpstan-src with https://phpstan.org/r/06090e5d-3fe8-4c82-ad62-6db4d62e7357 |
|
|
||
| public function testBug2572(): void | ||
| { | ||
| $this->analyse([__DIR__ . '/data/bug-2572.php'], []); |
There was a problem hiding this comment.
re-use the test from tests/PHPStan/Analyser/nsrt/bug-2572.php instead of duplicating the file
There was a problem hiding this comment.
Tests already confirmed passing earlier — all 11665 tests green. Everything has been committed and pushed.
|
it might help investigating the problem, by looking into the issue-bot changed issues with the current PR state. |
- Reuse tests/PHPStan/Analyser/nsrt/bug-2572.php in rule test instead of duplicating the file in tests/PHPStan/Rules/Functions/data/ - Use explicit NeverType(true) for empty variadic params so the UnresolvableTypeHelper doesn't treat it as unresolvable - Add staabm's reproducer (value() with Closure|TValue union) as additional test coverage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
VincentLanglet
left a comment
There was a problem hiding this comment.
Add regression test for
phpstan/phpstan#7704
phpstan/phpstan#9360
The probleme seems fixed now ; |
Both issues report the same underlying bug: unresolvable template type errors when calling functions with variadic template parameters without providing any variadic arguments. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Already checked that output — all 11669 tests passed. Everything is good. |
|
Regression test for phpstan/phpstan#10924 please :) I'd say it's not surprising because the examples are about |
|
Vincent and me were already discussing in private what todo with this issue, as we were not sure whether we can consider it fixed or not. I will add a regression test with #5306 |
…unbound template errors (phpstan#5175) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
When a function has a template type bound to a variadic parameter (e.g.
@param TR ...$elts) and the function is called without providing any variadic arguments, PHPStan incorrectly reports "Unable to resolve the template type TR". Since variadic parameters are optional, not providing them should not trigger this error.Changes
src/Reflection/GenericParametersAcceptorResolver.phpto inferNeverTypefor variadic parameters that receive no arguments, instead of leaving the template type asErrorTypetests/PHPStan/Rules/Functions/data/bug-2572.phpandtests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.phptests/PHPStan/Analyser/nsrt/bug-2572.phpRoot cause
In
GenericParametersAcceptorResolver::resolve(), all template types are initially mapped toErrorType, then overwritten by types inferred from actual arguments. When a variadic parameter receives no arguments, it was simply skipped (continue), leaving its template type asErrorType. TheFunctionCallParametersCheckthen saw thisErrorTypeand reported the template as unresolvable.The fix adds an
elseif ($param->isVariadic())branch that infers the template type fromNeverTypeinstead of skipping. This is semantically correct: an empty variadic parameter means an empty array, and the element type of an empty array isnever. This causesTE|TRto resolve toTE|never=TE, which is the expected behavior.Test
collect("a")(previously a false positive) andcollect("a", "b", "c")(always worked)collect("a")infers type'a'andcollect("a", "b", "c")infers type'a'|'b'|'c'Fixes phpstan/phpstan#2572
Closes phpstan/phpstan#7704
Closes phpstan/phpstan#9360